#ifndef StaticTView_First
#define StaticTView_First
#ifdef __GNUG__
#pragma interface
#endif

#include "ObjArray.h"
#include "Text.h"
#include "TextFormatter.h"
#include "View.h"

class TextPainter;
class TextPager;

enum TViewAlign {       // alignment of the view
	eTViewLeft,
	eTViewRight,
	eTViewCenter
};

enum TextViewFlags {
	eTextViewNone       =   0,
	eTextViewReadOnly   =   BIT(eViewLast+1),   // disable text modifications
	eTextViewInvis      =   BIT(eViewLast+2),   // show invisible characters
	eTextWantFindFocus  =   BIT(eViewLast+3),   // text view wants find focus
	eTextViewNoBatch    =   BIT(eViewLast+4),   // do not batch characters
	eTextViewModified   =   BIT(eViewLast+5),   // view size modified
	eTextViewDragAndDrop=   BIT(eViewLast+6),   // enable drag&drop
	eTextViewNoClip     =   BIT(eViewLast+7),   // clip at inner rectangle
	eTextViewLast       =   eViewLast+6,
	eTextViewDefault    =   eVObjEnabled
};

extern const Rectangle gFitRect;

const bool
	cWordWrap= TRUE,
	cNoWordWrap= !cWordWrap,
		
	cShowInvisibles= TRUE,
	cHideInvisibles= !cShowInvisibles,
		
	cRevealTop= TRUE,
	cDoNotRevealTop= FALSE;
		
const int
	cSizeVariable= -1,
	cFit= cSizeVariable;

//---- StaticTextView -------------------------------------------------------

class StaticTextView: public View {
public:
	MetaDef(StaticTextView);

	StaticTextView(EvtHandler *eh, const Rectangle &r, Text *t,
		bool wrap= cWordWrap, TextViewFlags= eTextViewDefault,
		const Point &border= gBorder, TViewAlign m= eTViewLeft,
		int id= cIdNone);
		// if contentRect.extent.y is set to cSizeVariable
		// extent.y is adapted to extent of largest text line
		
	~StaticTextView();

	//---- rendering
	void PrintAdorn(const Rectangle&, int gPageNo);
	void Draw(Rectangle);

	//---- composing
	virtual void Repair(int from, int to, bool redraw);
	virtual void RepairAll();    // reformat and redisplay whole text

	virtual void InvalidateRange(int from, int to);
	virtual void InvalidateRange(int from, const Point &fp, int to, const Point &tp);

	virtual Text *SetText(Text*, bool scroll= cRevealTop);     // returns old text
	void SetFormatter(TextFormatter *f);
	void SetPainter(TextPainter *tp);
	void SetPager(TextPager *tp);
		
	virtual void SetString(byte *str, int len= -1);

	Text *GetText();
		
	//---- acessing
	virtual void SetFont(Font*);
	TViewAlign GetAlignment();
	void SetAlign(TViewAlign);
	void ShowInvisibles(bool);
	bool GetShowInvis();
	void SetNoBatch(bool);
	bool GetNoBatch();
	void SetWordWrap(bool);
	bool GetWordWrap();
	bool Empty();
	int Lines();
	bool IsReadOnly();
	int NumberOfLines();

	//---- mapping
	virtual void PointToPoint(const Point &p, Point *viewPos= 0,
			int *lineNo= 0, int *CharNo= 0, bool relative= TRUE);
	virtual int CharToPoint(int charNo, int *lineNo= 0,
			Point *viewPos= 0, bool relative= TRUE);
	virtual Point LineToPoint(int line, bool basePoint= FALSE,
			bool relative= TRUE);
	virtual int PointToLine(const Point &p);
	virtual int CharToLine(int ch);   // return line number of character
	Rectangle NextPageBreak(int pageno, const Rectangle &r);

	//---- line structure access
	LineMark *MarkAtLine(int i);
	int StartLine(int l);
	int EndLine(int l);
	int LineHeight(int l);
	int BaseHeight(int l);

	//---- size managment
		// adapt view size to the extension of text if wrap is set to TRUE only
		// the height is changed
	void SetExtent(Point); // (reformats text)
	Metric GetMinSize();
	Point GetInnerOrigin();
	Point GetInnerExtent();
	void SetBorder(Point newBorder, bool repair= FALSE);
	Point GetBorder();

	//----- client marks
	void AddMark(Mark*);
	Mark *RemoveMark(Mark*);
	Iterator *GetMarkIter();
	MarkList *GetMarkList();

	//----- debugging
	void InspectorId(char*, int);
	void CollectParts(Collection*);

	//----- generic methods
	const char *AsString();
	OStream& PrintOn(OStream&);
	IStream& ReadFrom(IStream&);
	void Dump();
	void ClassInvariant();

	//---- static methods
	static Metric MeasureText(const char *txt, Font* fd, int minwidth, int nlines= 1);
	static void DrawBoxedText(const Rectangle &r, const char *txt, Font*, Ink *ink,
					bool wrap, VObjAlign a= (VObjAlign)(eVObjHLeft|eVObjVTop));

protected:
	Text *text;                 // shown text
	TextFormatter *formatter;   // formatter
	TextPainter *painter;       // text painter/mapper
	TextPager *pager;           // break view into pages
	TViewAlign align;           // view alignment
	bool wrap;                  // break line at view boundary
	bool drawViewBorder;
	bool horExtend;
	Point border;               // border around the text

	int nLines;                 // number of lines
	ObjArray *lines;            // array of line marks, grows dynamically
	MarkList *marks;

	int cline;                  // line and position map cache
	int cYPosition;

	void Init(const Rectangle&, Text*, bool wrap, TextViewFlags,
						const Point &border, TViewAlign);
	int UpdateView(int from, int to, int n, bool redraw);
	void UpdateComposition(int from, int to, int n);
	void UpdateExtent(int dy);
	void InvalidateDiff(const Point &newExtent, const Point &newOrigin);
	int AlignView(int nexExtent);
	void SwapRange(int &a, int &b);

	virtual void DrawLine(const Point &p, int line,
			const Rectangle &lineRect, const Rectangle &clip);
};

inline TViewAlign StaticTextView::GetAlignment()
	{ return align; }
inline int StaticTextView::Lines()
	{ return nLines; }
inline int StaticTextView::NumberOfLines()
	{ return Lines(); }
inline Text *StaticTextView::GetText()
	{ return text; }        
inline bool StaticTextView::Empty()
	{ return text->Size() == 0; }
inline LineMark *StaticTextView::MarkAtLine(int i)
	{ return (LineMark*)(*lines)[i]; }
inline int StaticTextView::StartLine(int l)
	{ return MarkAtLine(l)->pos; }
inline int StaticTextView::EndLine(int l)
	{ return MarkAtLine(l)->pos + MarkAtLine(l)->len; }
inline Point StaticTextView::GetInnerOrigin()
	{ return contentRect.origin+border; }
inline Point StaticTextView::GetInnerExtent()
	{ return contentRect.extent-2*border; }
inline Point StaticTextView::GetBorder()
	{ return border; }
inline void StaticTextView::SwapRange(int &a, int &b)
	{ int tmp; tmp= a; a= b; b= tmp; }

#endif
